
package tetris.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.media.Codec;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

import com.sun.media.codec.audio.mp3.JavaDecoder;
import javax.media.PlugInManager;

import tetris.board.Board;

/**
 * 
 * The Awesome Tetris game UI.
 * 
 * @author Agari NLN (agarin@uw.edu)
 * @version 2.8
 * 
 */
public class GUI extends JFrame
{
  /**
   * This is here to avoid warnings.
   */
  private static final long serialVersionUID = 1L;

  /**
   * The default width.
   */
  private static final int DEFAULT_WIDTH = 350;
  
  /**
   * The default height.
   */
  private static final int DEFAULT_HEIGHT = 300;
  
  /**
   * The GUI of my Tetris board.
   */
  protected BoardGui my_board_gui;
  
  /**
   * The frame where the the Tetris board and pieces are going to be placed on.
   */
  private final JFrame my_frame;
  
  /**
   * A start up menu where it gives the user the basic instructions and 
   * allow the game to start.
   */
  private final JFrame my_start_menu;

  /**
   * The Tetris board, the logic portion.
   */
  private Board my_board;
  
  /**
   * The menus on the frame.
   */
  private final TheMenus my_menu_bar;

  /**
   * Construct the Tetris GUI.
   */
  public GUI()
  {
    super();
    my_frame = new JFrame();
    my_frame.setPreferredSize(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));
    my_frame.setMinimumSize(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));
    my_start_menu = new JFrame();
    my_start_menu.setPreferredSize(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));
    my_menu_bar = new TheMenus(this);
    initGUI();
  }

  /**
   * Initialize the GUI, make the board.
   */
  private void initGUI()
  {
    
    my_frame.setTitle("Tetris");
    my_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    my_frame.setLayout(new BorderLayout());
    
    
    final JButton start = new JButton("Start");
    my_start_menu.setTitle("New Game Tetris");
    my_start_menu.add(new JLabel("<html><b>Use Left/Right Arrows to Move Left/Right" + 
                                 "<br>Up Arrow to Rotate<br>Down Arrow to Move Down<br>" +
                                 "Space Bar to Instant Drop</html>"),
                      BorderLayout.CENTER);

    my_start_menu.add(start, BorderLayout.SOUTH);
    
    start.addActionListener(new ActionListener()
    {
      @Override
      public void actionPerformed(final ActionEvent the_event)
      {
        startRealGame();
      }
    });

  }

  /**
   * Put all elements of the GUI onto the frame and set the frame to visible.
   */
  private void start()
  {
    my_start_menu.setVisible(true);
    my_start_menu.pack();
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }
  
  /**
   * Initialize the real Tetris game for play.
   */
  public void startRealGame()
  {
    GameInfo game_info;
    my_frame.setJMenuBar(my_menu_bar);
    my_board = new Board();
    my_board_gui = new BoardGui(my_board);
    game_info = new GameInfo(my_board);
    my_board.startTimer();
    my_frame.add(my_board_gui, BorderLayout.CENTER);
    my_frame.add(game_info, BorderLayout.WEST);
    final KeyboardFocusManager manager = 
      KeyboardFocusManager.getCurrentKeyboardFocusManager();
    manager.addKeyEventDispatcher(new TetrisDispatcher(my_board));
    my_start_menu.setVisible(false);
    my_frame.setVisible(true);
    my_frame.pack();
  }

  /**
   * Start the game!
   * 
   * @param the_args does nothing
   */
  public static void main(final String[] the_args)
  {
    final Codec c = new JavaDecoder();
    PlugInManager.addPlugIn("com.sun.media.codec.audio.mp3.JavaDecoder", 
                            c.getSupportedInputFormats(), 
                            c.getSupportedOutputFormats(null), PlugInManager.CODEC);
    new GUI().start();
  }

  /**
   * End the current game.
   */
  public void exit()
  {
    my_frame.setVisible(false);
    dispose();
  }
  
  /**
   * Get the logic Tetris board.
   * @return the logic Tetris board.
   */
  public Board getBoard()
  {
    return my_board;
  }

  /**
   * The controls of the Tetris game.
   * 
   * @author Agari NLN (agarin@uw.edu)
   * @version 2.8
   * 
   */
  private static class TetrisDispatcher implements KeyEventDispatcher
  {
    /**
     * Board to manipulate when keys are pressed.
     */
    private final Board my_board;

    /**
     * Creates a keyboard event dispatcher for Tetris board.
     * 
     * @param the_board The graphical part of
     */
    public TetrisDispatcher(final Board the_board)
    {
      my_board = the_board;
    }

    @Override
    public boolean dispatchKeyEvent(final KeyEvent the_e)
    {
      final int key = the_e.getKeyCode();
      
      
      if (the_e.getID() == KeyEvent.KEY_PRESSED && key == KeyEvent.VK_DOWN)
      {
        my_board.moveDown();
      }

      if (the_e.getID() == KeyEvent.KEY_RELEASED &&
          my_board.getCurrentPiece().myPosition().y >= 0)
      {
        switch (key)
        {
          case KeyEvent.VK_UP: // up arrow
          case KeyEvent.VK_KP_UP:
            my_board.rotateLeft();
            break;
          case KeyEvent.VK_LEFT: // left arrow
          case KeyEvent.VK_KP_LEFT:
            my_board.moveLeft();
            break;
          case KeyEvent.VK_RIGHT: // right arrow
          case KeyEvent.VK_KP_RIGHT:
            my_board.moveRight();
            break;
          case KeyEvent.VK_SPACE: // space bar to instant drop
            my_board.instantDrop();
            break;
          default:
            break;
        }
      }
      return false;
    }
  }
}
